package ecole.organisation;

import java.util.ArrayList;
import java.util.Date;

import config.Config;
import ecole.infrastructure.Salle;
import ecole.utilisateur.Etudiant;
import ecole.utilisateur.Professeur;

/**
 * Classe définissant les diférentes formation d'une école
 * 
 * @author Salah Bennour
 */
public class Formation implements java.io.Serializable{
	
	private static final long serialVersionUID = 2L;
	private ArrayList<Groupe> listeGroupeAmphi = new ArrayList<Groupe>();
	private ArrayList<Groupe> listeGroupeTD = new ArrayList<Groupe>(); 
	private ArrayList<Groupe> listeGroupeTP = new ArrayList<Groupe>();
	private ArrayList<Enseignement> listeEnseignement = new ArrayList<Enseignement>();
	private String nomFormation,idFormation;
	private int anneeFormation;// 3 4 5
	private final static int maxEtudiantsFormation = Config.MAX_ETUD_FORMATION;
	private final static int maxEnseignementFormation = Config.MAX_ENS_FORMATION;
	private Professeur respoFormation;
	
	// ***************CONSTRUCTEURS*************************
	public Formation(){}

	public Formation(String nomFormation, int anneeFormation, Professeur professeur){
		this.nomFormation = nomFormation;
		this.anneeFormation = anneeFormation;
		this.idFormation = nomFormation + Integer.toString(anneeFormation);
		
		listeGroupeAmphi.add(new Groupe(3, "GroupeAmphi"));
		
		for(int i = 0; i< 4; i++)
			listeGroupeTD.add(new Groupe(1, "GroupeTD"+(i+1)));
		
		for(int i = 0; i< 7; i++)
			listeGroupeTP.add(new Groupe(2, "GroupeTP"+(i+1)));
		
		if(professeur.isResponsableFormation())
			System.out.println("Ce professeur est deja responsable d'une formation !");
		else
		{
			this.respoFormation=professeur;
			this.respoFormation.setResponsableFormation(true);
		}
	}

	// ***************METHODES*************************
	/**
	 * Methode permettant de supprimer un enseignement d'une formation
	 * @param i est l'indice dans la liste des enseignements de la formation
	 */
	public void supprimerUnEnseignement(int i){
		listeEnseignement.remove(i);
	}
	/**
	 * Methode permettant de supprimer la liste des enseignement d'une formation
	 */
	public void supprimerListeEnseignement(){
		listeEnseignement.clear();
	}
	/**
	 * Methode permettant d'ajouter un etudiant à la liste d'etudiant de la formation.
	 * @param student est l'instance de la classe Etudiant que l'on souhaite ajouter a une formation et donc un groupe.
	 */
	public void ajouterEtudiant(Etudiant student){
		Groupe grpTD = listeGroupeTD.get(0);
		int nbEtudTotal = 0;
		for(Groupe g : listeGroupeTD)
		{
			nbEtudTotal += g.getListEtudiant().size(); //somme des listes des etudiants des groupes d'une formation
			if ( grpTD.getListEtudiant().size() > g.getListEtudiant().size() )	// On cherche le groupe le plus petit
				grpTD = g;
		}
		//Idem pour les groupe de Tp
		
		Groupe grpTP = listeGroupeTP.get(0);
		for(Groupe g : listeGroupeTP)
		{
			if ( grpTP.getListEtudiant().size() > g.getListEtudiant().size() )	// On cherche le groupe le plus petit
				grpTP = g;
		}
		if(nbEtudTotal < maxEtudiantsFormation){
			grpTP.ajouterEtudiant(student); //ajoute etudiant dans le groupe td le plus petit
			grpTD.ajouterEtudiant(student); //ajoute etudiant dans le groupe tp le plus petit
			listeGroupeAmphi.get(0).ajouterEtudiant(student); //ajoute au groupe amphi
		}
		else
			System.out.println("Il y a deja trop d'etudiant dans cette formation !"); 
		
	}
	
	/**
	 * Methode permettant d'ajouter une seance à un groupe d'une formation donnée.
	 * @param ens est l'instance de la classe Enseignement.
	 * @param prof est l'instance de la classe Professeur.
	 * @param date est l'instance de la classe Date.
	 * @param creneau est un numero correspondant à un créneau horaire.
	 * @param salle est l'instance de la classe Salle.
	 * @param grp est l'instance de la classe Groupe.
	 */
	public void ajouterSeance(Enseignement ens,Professeur prof, Date date ,int creneau, Salle salle, Groupe grp){
		// Cherche le groupe(->grp) dans la liste des groupe de la formation (->listeGRoupe) => groupeTrouve
		Groupe gpTrouve = null; 
		//VERIFICATION GOUPE TD
		for (int i =0 ; i< listeGroupeTD.size() ; i++)
		{
			if(listeGroupeTD.get(i).equals(grp)) // si un groupe de la liste de listeGroupe est égale à grp
				gpTrouve = listeGroupeTD.get(i);
		}
		if(gpTrouve == null){
			//VERIFICATION GOUPE TP
			for (int i =0 ; i< listeGroupeTP.size() ; i++)
			{
				if(listeGroupeTP.get(i).equals(grp)) // si un groupe de la liste de listeGroupe est égale à grp
					gpTrouve = listeGroupeTP.get(i);
			}
		}
		if(listeGroupeAmphi.get(0).equals(grp))
			gpTrouve = listeGroupeAmphi.get(0);
		if(gpTrouve == null){
			System.out.println("Ce groupe n'existe pas dans cette formation !!");
			return;
		}
		
		// Cherche enseignement dans la liste des enseignement de la formation (->listeEnseignement) => ensTrouve
		Enseignement ensTrouve = null;
		for (int i =0 ; i< listeEnseignement.size() ; i++)
		{
			if(listeEnseignement.get(i).equals(ens)) // si un groupe de la liste de listeEnseignement est égale à grp
				ensTrouve = listeEnseignement.get(i);
		}
		if(ensTrouve == null) 
		{
			System.out.println("Cet enseignement n'existe pas !!");
			return;
		}
		// Appelle la methode ajouterSeance de la classe Groupe en faisant :
		gpTrouve.ajouterSeance(ensTrouve, prof, date, creneau, salle);
	}

  /** 
  * Methode permettant de changer d'etudiant de groupe en passant en parametre un etudiant, un groupe de depart et d'arriver
  * @param student est l'etudiant que l'on souhaite changer de groupe
  * @param grpDepart est le groupe auquel fais partie l'etudiant
  * @param grpArrive est le nouveau groupe de l'etudiant
  */
	public void changerEtudiantGroupe(Etudiant student, Groupe grpDepart, Groupe grpArrive){
		boolean groupeTD;
		if(listeGroupeTD.contains(grpDepart) && listeGroupeTD.contains(grpArrive))
			groupeTD = true;
		else if(listeGroupeTP.contains(grpDepart) && listeGroupeTP.contains(grpArrive))
			groupeTD = false;
		else 
			return;
		
		if(groupeTD){
			if(grpDepart.etudiantAppartientGroupe(student)) // si etudiant appartien au groupe de depart
				if(listeGroupeTD.contains(grpDepart)) // si groupe de depart est bien dans la formation
					if(listeGroupeTD.contains(grpArrive)) // si groupe d'arriver est bien de la formation
						if(grpArrive.isNbEtudiantInfCapacite()){ // si le groupe d'arriver n'est pas complet
							grpArrive.ajouterEtudiant(student); // ajoute etudiant au groupe d'arriver
							grpDepart.supprimerEtudiant(student); //supprime etudiant du groupe precedent
						}
						else System.out.println("Groupe : "+grpArrive.getNomGroupe()+" est complet");
					else System.out.println("Le groupe d'arrivé n'est pas de la formation :" +getNomFormation());
				else System.out.println("Le groupe de depart n'est pas de la formation :" +getNomFormation());
			else System.out.println("L'etudiant " +student.getNom()+ " "+student.getPrenom()+ " n'appartient pas au groupe de départ");
		}
		
		else if(! groupeTD){
			if(grpDepart.etudiantAppartientGroupe(student)) // si etudiant appartien au groupe de depart
				if(listeGroupeTP.contains(grpDepart)) // si groupe de depart est bien dans la formation
					if(listeGroupeTP.contains(grpArrive)) // si groupe d'arriver est bien de la formation
						if(grpArrive.isNbEtudiantInfCapacite()){ // si le groupe d'arriver n'est pas complet
							grpArrive.ajouterEtudiant(student); // ajoute etudiant au groupe d'arriver
							grpDepart.supprimerEtudiant(student); //supprime etudiant du groupe precedent
						}
						else System.out.println("Groupe : "+grpArrive.getNomGroupe()+" est complet");
					else System.out.println("Le groupe d'arrivé n'est pas de la formation :" +getNomFormation());
				else System.out.println("Le groupe de depart n'est pas de la formation :" +getNomFormation());
			else System.out.println("L'etudiant " +student.getNom()+ " "+student.getPrenom()+ " n'appartient pas au groupe de départ");
		}
	}
	
	/** 
	 * Methode permettant de supprimer un etudiant à un groupe
	 * @param student est l'etudiant que l'on souhaite supprimer de groupe
	 * @param grp est le groupe ou l'etudiant fais partie
	 */
	public void supprimerEtudiant(Etudiant student){
		//suppresion du groupe de TP
		for(int i=0; i<listeGroupeTD.size(); i++)
			for(int j=0; j<this.listeGroupeTD.get(i).getListEtudiant().size(); j++)
				if (this.listeGroupeTD.get(i).getListEtudiant().get(j).equals(student))
					this.listeGroupeTD.get(i).supprimerEtudiant(this.listeGroupeTD.get(i).getListEtudiant().get(j));
	
		//suppresion du groupe de TD
		for(int i=0; i<listeGroupeTP.size(); i++)
			for(int j=0; j<this.listeGroupeTP.get(i).getListEtudiant().size(); j++)
				if (this.listeGroupeTP.get(i).getListEtudiant().get(j).equals(student))
					this.listeGroupeTP.get(i).supprimerEtudiant(this.listeGroupeTP.get(i).getListEtudiant().get(j));
		
		//suppresion du groupe d'amphi
		if(listeGroupeAmphi.get(0).getListEtudiant().contains(student))
			this.listeGroupeAmphi.get(0).supprimerEtudiant(student);
		
	}
	/**
	 * Methode permettant d'ajouter un groupe à la liste des groupe de la formation.
	 * @param nomGroupe est une chaine de caractere définissant le nom du groupe.
	 */
	public void ajouterGroupe(int type, String nomGroupe){
		if(type == 1){
			if(listeGroupeTD.size() < 4){
				Groupe grp = new Groupe(1, nomGroupe);
				listeGroupeTD.add(grp);
			}
			else 
				System.out.println("Impossible d'ajouter d'autre groupe. Il y en a deja 4.");
		}
		else if(type == 2){
			if(listeGroupeTP.size() < 7){
				Groupe grp = new Groupe(2, nomGroupe);
				listeGroupeTP.add(grp);
			}
			else 
				System.out.println("Impossible d'ajouter d'autre groupe. Il y en a deja 7.");
		}
	}

	/** 
	 * Methode permettant de verifier si un enseignement existe deja dans la formation.
	 * @param ens est l'instance de la classe Enseignment.
	 * @return true si l'enseignement existe deja dans la formation. Sinon return false.
	 */
	public boolean enseignementExiste(Enseignement ens){
		if(listeEnseignement.isEmpty())  //si la liste listeEnseignement est vide
			return false; 
		for(int i=0; i<listeEnseignement.size(); i++){
			// si le nom de l'enseignement est égale à un nom de l'enseignement de la liste
			if(listeEnseignement.get(i).getNomEnseignement().equals(ens.getNomEnseignement()))
				return true;
		}
		return false;
	}

	/** 
	 * Methode permettant de verifier si le nombre d'enseignement de la formation n'a pas dépassé le seuil autorisé
	 * @return true si le nombre d'enseignement de la formation a dépassé le seuil l'égale. Sinon retourne false.
	 */
	public boolean nombreEnseignementAtteind() {
		if (listeEnseignement.size() <= maxEnseignementFormation) // si nombre enseignement <= 10
			return false;
		else 
			return true;
	}

	/**
	 * Methode permettant d'ajouter un enseignement a la liste des enseignements de la formation.
	 * @param ens est l'instance de la classe Enseignement que l'on souahite ajouter a la formation.
	 */
	public void ajouterEnseignement(Enseignement ens){
		if (!enseignementExiste(ens)){ //si l'enseignement existe deja dans cette formation
			if (!nombreEnseignementAtteind()){ // si nombre d'enseignement >=10
				listeEnseignement.add(ens); //ajoute l'enseignement à la liste des enseignement du groupe
			} 
			else System.out.println("Il y a deja 10 enseignements danc cette formation on ne peut donc plus en ajouter");
		}
		else System.out.println("L'enseignement existe déja dans cette formation !");
	}

	// ***************GETTER*************************	
	/** 
	 *Methode permettant de retourner le nombre de groupe(s) de td d'une formation.
	 * @return int : le nombre de groupe(s) de td d'une formation.
	 */
	public int getNbGroupeTD(){
		return listeGroupeTD.size();
	}
	/** 
	 *Methode permettant de retourner le nombre de groupe(s) de tp d'une formation.
	 * @return int : le nombre de groupe(s) tp d'une formation.
	 */
	public int getNbGroupeTP(){
		return listeGroupeTP.size();
	}
	
	
	/**
	 * Methode permettant d'obtenir tous les enseignements de l'ecole.
	 * @return ArrayList<Enseignement> : tous les enseignements de l'ecole. 
	 */
	public ArrayList<Enseignement> getListeEnseignement() {
		return listeEnseignement;
	}
	
	/**
	 * Methode permettant de retourner la liste des etudiants d'une formation.
	 * @return ArrayList<Etudiant> de la formation.
	 */
	public ArrayList<Etudiant> getListeEtudiant(){
		ArrayList<Etudiant> al = new ArrayList<Etudiant>();
		for ( Groupe g : this.listeGroupeTD) //parcours tous les groupes de la formation
			al.addAll(g.getListEtudiant()); //ajoute tous les étudiants de chaque groupe dans al
		return al;
	}

	
	/** 
	 *Methode permettant de retouner l'identifiant de la formation(ex: SI3, SI4, MAM3..)
	 * @return String : l'id de la formation
	 */
	public String getIdFormation() {
		return idFormation;
	}

	/** 
	 *Methode permettant d'afficher le ieme groupe de td d'une formation.
	 * @param i : le ieme groupe de td d'une formation.
	 * @return Groupe : le ieme groupe.
	 */  
	public Groupe getGroupeTD(int i){
		return listeGroupeTD.get(i);
	}
	
	/** 
	 *Methode permettant d'afficher le ieme groupe de tp d'une formation.
	 * @param i : le ieme groupe de td d'une formation.
	 * @return Groupe : le ieme groupe.
	 */  
	public Groupe getGroupeTP(int i){
		return listeGroupeTP.get(i);
	}

	/** 
	 *Methode permettant de retourner le nombre maximal d'etudiants par formation.
	 * @return int : le nombre d'etudiants maximal par formation.
	 */
	public int getMaxEtudiantsFormation(){
		return maxEtudiantsFormation;
	}

	/** 
	 *Methode permettant de retourner tous les groupes de td d'une formation
	 * @return ArrayList<Groupe> : est la liste de groupe de td
	 */
	public ArrayList<Groupe> getListeGroupeTD(){
		return listeGroupeTD;
	}
	
	/** 
	 *Methode permettant de retourner tous les groupes de tp d'une formation
	 * @return ArrayList<Groupe> : est la liste de groupe de tp
	 */
	public ArrayList<Groupe> getListeGroupeTP(){
		return listeGroupeTP;
	}
	
	/** 
	 *Methode permettant de retourner tous le groupe d'amphi
	 * @return ArrayList<Groupe> : est le groupe d'amphi
	 */
	public Groupe getGroupeAmphi(){
		return listeGroupeAmphi.get(0);
	}
	
	/** 
	 *Methode permettant de retourner le nom de la formation.
	 * @return String : le nom de la formation.
	 */
	public String getNomFormation(){
		return nomFormation;
	}

	/** 
	 *Methode permettant de retourner l'année de la formation.
	 * @return int : l'année de la formation.
	 */
	public int getAnneeFormation(){
		return anneeFormation;
	}

	/** 
	 *Methode permettant de retourner le professeur reponsable de la formation.
	 * @return Professeur : le professeur responsable de la formation.
	 */
	public Professeur getRespoFormation() {
		return respoFormation;
	}

	/** 
	 *Methode permettant de retourner le nombre d'enseignement dans la formation.
	 * @return int : le nombre d'enseignement dans la formation.
	 */
	public int getNombreEnseignement(){
		return listeEnseignement.size();
	}

	/** 
	 *Methode permettant d'afficher le ieme enseignement de la liste d'enseignement de la formation.
	 * @param i est l'indice i de la liste d'enseignement de la formation.
	 * @return Enseignement : le ieme enseignement de la liste de la formation.
	 */
	public Enseignement getEnseignement(int i){
		return listeEnseignement.get(i);
	}

	// ***************SETTER*************************
	/** 
	 * Methode permettant de modifier le professeur responsable de la formation
	 * La methode fais appel a la methode responsableFormation() de la classe professeur afin de modifier le boolean.
	 * @param prof est l'instance de la classe Professeur. C'est le nouveau professeur.
	 */
	public void setResponsableFormation(Professeur prof){
		if(prof.isResponsableFormation()) //si le professeur est deja responsable d'une formation
			System.out.println("Impossible le professeur" +prof.getNom()+" " +prof.getPrenom()+ "est deja responsable d'une formation");
		else{
			this.respoFormation.setResponsableFormation(false); //Ancien professeur resp : n'est plus reponsable de la formation
			prof.setResponsableFormation(true); // Nouveau professeur : est responsable de la formation
			this.respoFormation = prof; //assignation
		}
	}


	// ***************TO STRING*************************
	public String toString(){
		return "FORMATION \n \t Nom :" +getNomFormation()+ 
		"\n \t Annee :" +getAnneeFormation() +
		"\n \t Professeur responsable :" +respoFormation.getNom()+  " " +respoFormation.getPrenom()+ "\n";
	}
}

